package com.hfengxiang.example.canvasrotatedemo;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;

import androidx.annotation.Nullable;

public class MatrixView2 extends View implements RotateProcessor.OnRotateListener {

    Matrix matrix = new Matrix();
    Matrix savedMatrix = new Matrix();
    private Paint paint;
    private Bitmap bitmap;
    private float currentScale;
    private RotateProcessor rotateProcessor;
    private float lastTotal;
    private RectF testRect;

    public MatrixView2(Context context) {
        this(context, null);
    }

    public MatrixView2(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, -1);
    }

    public MatrixView2(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        this(context, attrs, defStyleAttr, -1);
    }

    public MatrixView2(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init();
    }

    private void init() {
        paint = new Paint();
        paint.setAntiAlias(true);
        bitmap = Utils.getPhoto(getResources(), getResources().getDisplayMetrics().widthPixels);
        rotateProcessor = new RotateProcessor();
        rotateProcessor.setRotateListener(this);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.translate(getWidth() / 2f, getHeight() / 2f);
        canvas.drawBitmap(bitmap, matrix, paint);
        if(testRect!=null){
            paint.setColor(Color.GREEN);
            paint.setStyle(Paint.Style.STROKE);
            canvas.drawRect(testRect,paint);
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getActionMasked()) {
            case MotionEvent.ACTION_DOWN:
            case MotionEvent.ACTION_POINTER_DOWN:
                rotateProcessor.handleActionDown(event);
                break;
            case MotionEvent.ACTION_MOVE:
                rotateProcessor.handleActionMove(event);
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_POINTER_UP:
                rotateProcessor.handleActionUp(event);
                break;
        }
        return true;
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        currentScale = ScaleCalculator.calculateScale(getWidth(), getHeight(), bitmap.getWidth(), bitmap.getHeight(), 0);
        matrix.postTranslate(-bitmap.getWidth() / 2f, -bitmap.getHeight() / 2f);
        matrix.postScale(currentScale, currentScale);
    }

    @Override
    public void onRotate(RotateInfo rotateInfo) {
        if(rotateInfo.isRecovering()){
            matrix.set(savedMatrix);
            matrix.postRotate(rotateInfo.getTotalDegree(), rotateInfo.getRotateCenter().x-getWidth()/2f,
                    rotateInfo.getRotateCenter().y-getHeight()/2f);
            fixTranslation();
            invalidate();
        }else {
            testRect = new RectF(0, 0, bitmap.getWidth(), bitmap.getHeight());
            matrix.mapRect(testRect);
            Log.i("MapRect", testRect.toShortString());

            matrix.set(savedMatrix);
            matrix.postRotate(rotateInfo.getTotalDegree(),rotateInfo.getRotateCenter().x-getWidth()/2f,
                    rotateInfo.getRotateCenter().y-getHeight()/2f);
        }
        invalidate();
    }

    private void fixTranslation() {
        RectF rect = new RectF(0, 0, bitmap.getWidth(), bitmap.getHeight());

        matrix.mapRect(rect);

        float height = rect.height();

        float width = rect.width();

        float deltaX = 0, deltaY = 0;

        if (width < bitmap.getWidth()) {
            deltaX = (bitmap.getWidth() - width) / 2 - rect.left;

        } else if (rect.left > 0) {
            deltaX = -rect.left;

        } else if (rect.right < bitmap.getWidth()) {
            deltaX = bitmap.getWidth() - rect.right;

        }

        if (height < bitmap.getHeight()) {
            deltaY = (bitmap.getHeight() - height) / 2 - rect.top;

        } else if (rect.top > 0) {
            deltaY = -rect.top;

        } else if (rect.bottom < bitmap.getHeight()) {
            deltaY = bitmap.getHeight() - rect.bottom;

        }

        matrix.postTranslate(deltaX, deltaY);

    }

    @Override
    public void onRotateStart(RotateInfo rotateInfo) {
        savedMatrix.set(matrix);
    }

    @Override
    public void onRecoverStart(RotateInfo info) {

    }

    @Override
    public void onRotateEnd(RotateInfo rotateInfo) {

    }

    @Override
    public float[] onCalculateScale(float targetDegree) {
        targetDegree = computeTargetDegree(targetDegree);
        float targetScale = ScaleCalculator.calculateScale(getWidth(), getHeight(), bitmap.getWidth(), bitmap.getHeight(), (int) targetDegree);
//        Log.i("onCalculateScale", "targetScale=" + targetScale);
        return new float[]{currentScale, targetScale};
    }

    /**
     * 根据旋转的角度计算出图片复位应当到达的角度
     *
     * @param degree 旋转的角度
     * @return 目标角度
     */
    private int computeTargetDegree(double degree) {
        int[] degrees = {0, 90, 90, 180, 180, 270, 270, 360};
        degree = degree % 360;
        int index = (int) (degree / 45);
        if (index > 0) {
            return degrees[index];
        } else {
            return -1 * degrees[-1 * index];
        }
    }
}
